---
title: Supabase
description: Deploy your MCP server on Supabase Edge Functions
icon: "); -webkit-mask-image: url('https://simpleicons.org/icons/supabase.svg'); mask-image: url('https://simpleicons.org/icons/supabase.svg');/*"
---

This guide demonstrates how to deploy an MCP server on [Supabase Edge Functions](https://supabase.com/docs/guides/functions), which runs on Deno and provides a serverless environment for your MCP applications.

## Prerequisites

1. **Supabase CLI**: Install from [Supabase CLI Installation Guide](https://supabase.com/docs/guides/cli)
2. **Supabase Account**
3. **Docker** Required to solve bug https://github.com/orgs/supabase/discussions/32815
4. **Node.js/Bun**: For building your MCP server

<iframe
  className="w-full aspect-video rounded-xl"
  src="https://www.youtube.com/embed/xua76KPhH9A"
  title="Deploying MCP Server to Supabase"
  frameBorder="0"
  allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
  allowFullScreen
></iframe>

## Create your mcp-use project

```bash
npx create-mcp-use-app your-project-name
```

This will create a new directory called `your-project-name` with a basic MCP server setup.

## Install dependencies

```bash
cd your-project-name
yarn
```

## Init supabase project

```bash
supabase init
```

This will create a new directory called `supabase` with a basic Supabase project setup.

## Quick Deployment

Deploy your MCP server to Supabase in one command using our automated deployment script:

```bash
# Download and run the deployment script (interactive mode)
curl -fsSL https://url.mcp-use.com/supabase | bash
```

Or download the script first to review it:

```bash
# Download the script
curl -fsSL https://url.mcp-use.com/supabase -o deploy.sh
chmod +x deploy.sh

# Run with your project ID
./deploy.sh YOUR_PROJECT_ID

# Optional: specify custom function name and bucket name
./deploy.sh YOUR_PROJECT_ID my-function-name my-bucket-name
```

Done!
You can now inspect your MCP server at https://inspector.mcp-use.com

### What the script does

The deployment script automatically:

1. ✅ Validates Supabase CLI installation and authentication
2. ✅ Checks if the project is initialized and linked
3. ✅ Patches `config.toml` with your project ID
4. ✅ Builds your MCP application with the correct `MCP_URL` and `MCP_SERVER_URL`
5. ✅ Copies build artifacts to the function directory
6. ✅ Sets `MCP_URL` and `CSP_URLS` (Supabase project URL) environment variables
7. ✅ Deploys the function to Supabase Edge Functions
8. ✅ Uploads widgets to the storage bucket

<Note>
  **Prerequisites for the script** - Supabase CLI installed (`npm install -g
  supabase`) - Logged in to Supabase (`supabase login`) - Docker running (for
  deployment)
</Note>

For manual deployment or to understand each step in detail, continue reading below.

## Manual Deployment

### Setting Up Your MCP Server for Supabase

### 1. Initialize a Supabase Project

If you don't have a Supabase project yet:

```bash
supabase init
```

### 2. Create an Edge Function

```bash
supabase functions new mcp-server
```

This creates a new function at `supabase/functions/mcp-server/`.

### 3. Adapt your MCP Server to use Deno (required for Supabase Edge Functions)

Widgets in the resources folder are automatically registered. Additional widgets can be registered manually. (see [UI Widgets](/typescript/server/ui-widgets))

<Note>
**Complete Example**

A full working example is available in the repository: [Supabase Example](https://github.com/mcp-use/mcp-use/tree/main/libraries/typescript/packages/mcp-use/examples/server/supabase)

</Note>

```typescript
// supabase/functions/mcp-server/index.ts

import { MCPServer } from "https://esm.sh/mcp-use@latest/server";

const PROJECT_REF = Deno.env.get("SUPABASE_PROJECT_REF") || "your-project-ref";
const BASE_URL =
  Deno.env.get("MCP_URL") ||
  `https://${PROJECT_REF}.supabase.co/functions/v1/mcp-server`;

// Create the mcp-use MCP server instance
const server = new MCPServer({
  name: "test-app",
  version: "1.0.0",
  description:
    "MCP server with automatic UI widget registration deployed on Supabase",
  baseUrl: BASE_URL,
});

// Define your tools
server.tool({
  name: "get-my-city",
  description: "Get my city",
  cb: async () => {
    return { content: [{ type: "text", text: `My city is San Francisco` }] };
  },
});
await server.listen();
```

### 4. Widgets assets

Widget assets should be served from a CDN, for example Supabase Storage.
Upload the <ins>**content**</ins> of the dist/resources/widgets folder to Supabase Storage and set the MCP_URL environment variable to the URL of the dist folder.

E.g if you created a bucket called "widgets" in Supabase Storage:

```bash
# UPLOAD
supabase storage cp -r dist/resources/widgets ss://widgets/ --experimental
```

and then set the environment variables for Supabase deployments:

```bash
# MCP_URL: Where widget assets (JS/CSS) are stored
export MCP_URL="https://YOUR_PROJECT_REF.supabase.co/storage/v1/object/public/widgets"

# MCP_SERVER_URL: Where the MCP server runs (for API calls in widgets)
export MCP_SERVER_URL="https://YOUR_PROJECT_REF.supabase.co/functions/v1/YOUR_FUNCTION_NAME"

# CSP_URLS: Supabase project URL (for Content Security Policy)
export CSP_URLS="https://YOUR_PROJECT_REF.supabase.co"
```

<Note>
**URLs Required**: Supabase deployments need these URLs because widget files are served from static storage while API calls go to the edge function:
- `MCP_URL`: Where widget assets are stored
- `MCP_SERVER_URL`: Enables build-time URL injection for static deployments
- `CSP_URLS`: Whitelists the Supabase project domain in the Content Security Policy (use base URL without path)
</Note>

### 5. Build the mcp-use app

```bash
echo $MCP_URL
# should output: https://YOUR_PROJECT_REF.supabase.co/storage/v1/object/public/widgets
echo $MCP_SERVER_URL
# should output: https://YOUR_PROJECT_REF.supabase.co/functions/v1/YOUR_FUNCTION_NAME
pnpm build
```

### 6. Copy the dist folder to the function directory

```bash
cp -r dist supabase/functions/mcp-server/
```

### 7. Configure the function in config.toml

```toml
[functions.mcp-server]
...
static_files = [ "./functions/mcp-server/dist/**/*.html", "./functions/mcp-server/dist/mcp-use.json" ]
...
```

### 8. Set Environment Variables for CSP

Set environment variables **before deploying** so the MCP server can configure Content Security Policy (CSP) to allow widgets to make API calls and load assets:

```bash
# MCP_URL: Server URL for API calls
supabase secrets set MCP_URL="https://YOUR_PROJECT_REF.supabase.co/functions/v1/mcp-server" --project-ref YOUR_PROJECT_REF

# CSP_URLS: Supabase project URL (without path) to allow storage and function access
supabase secrets set CSP_URLS="https://YOUR_PROJECT_REF.supabase.co" --project-ref YOUR_PROJECT_REF
```

<Note>
**Environment Variables:**
- `MCP_URL`: Whitelists the edge function domain for API calls from widgets
- `CSP_URLS`: Whitelists the Supabase project URL (without path) for widget assets (JS/CSS) and storage access. Use the base project URL like `https://nnpumlykjksvxivhywwo.supabase.co` (no `/storage/*` or other paths needed). Supports comma-separated values for multiple domains.

**Important**: Set these before deploying the function. If you set them after deployment, you must redeploy for the changes to take effect.

**Alternative**: You can also configure CSP per-widget in your widget's `appsSdkMetadata['openai/widgetCSP']` instead of using the global `CSP_URLS` environment variable. See [UI Widgets documentation](/typescript/server/ui-widgets#apps-sdk-metadata) for examples.
</Note>

### 9. Deploy the Function

```bash
supabase functions deploy mcp-server --use-docker
```

## Using the MCP Server

You can connect to the MCP Server from any MCP client. Below are examples for browser and Node.js using the `mcp-use` library.

### The MCP Server URL

```typescript
// From your application
//const mcpUrl = `https://YOUR_PROJECT_ID.supabase.co/functions/v1/FUNCTION_NAME/mcp`;
// e.g. if your function name is "mcp-server" as above
const mcpUrl = `https://YOUR_PROJECT_ID.supabase.co/functions/v1/mcp-server/mcp`;
```

### Browser/Client-Side Usage

```typescript
import { BrowserMCPClient } from "mcp-use";

const client = new BrowserMCPClient({
  mcpServers: {
    supabase: {
      url: `https://YOUR_PROJECT_ID.supabase.co/functions/v1/mcp-server/mcp`,
      transport: "http",
      headers: {
        Authorization: `Bearer ${SUPABASE_ANON_KEY}`,
        "Content-Type": "application/json",
        Accept: "application/json, text/event-stream",
      },
    },
  },
});

// Create a session and initialize
const session = await client.createSession("supabase");
await session.initialize();

// Now use the session to call tools, access resources, etc.
const response = await session.connector.callTool("greet", { name: "World" });
```

#### Node.js Usage

```typescript
import { MCPClient } from "mcp-use";

const client = new MCPClient({
  mcpServers: {
    supabase: {
      url: `https://YOUR_PROJECT_ID.supabase.co/functions/v1/mcp-server/mcp`,
      transport: "http",
      headers: {
        Authorization: `Bearer ${SUPABASE_ANON_KEY}`,
        "Content-Type": "application/json",
        Accept: "application/json, text/event-stream",
      },
    },
  },
});

// Create a session and initialize
const session = await client.createSession("supabase");
await session.initialize();

// Now use the session to call tools, access resources, etc.
const response = await session.connector.callTool("greet", { name: "World" });
```

<Warning>
**Important: Docker Required for Static Files**

Static files configured in `static_files` are **only bundled when Docker is running** during deployment. This applies to both local development and production deployment.

When deploying with `supabase functions deploy`, use the --use-docker flag.

```bash
docker info  # Verify Docker is running
supabase functions deploy mcp-server --use-docker
```

See the [Supabase static files documentation](https://github.com/orgs/supabase/discussions/32815) for more details.

</Warning>

### CORS Issues

- Ensure your CORS headers are correctly configured
- Check that the Accept header is included in requests
- Verify your Authorization header has the correct token

### "Initialising login role..." Appears Multiple Times

During deployment, you'll see `Initialising login role...` appear 2-3 times. This is **normal behavior** - the Supabase CLI authenticates separately for:
1. Project linking
2. Widget file upload to storage
3. Public file upload to storage

Each storage operation requires its own authentication.

### Deployment Stuck on "Initialising login role..."

If the deployment script **hangs** at `Initialising login role...` (no progress for several minutes) or you see authentication errors, Supabase may have temporarily banned your IP address. This is a [known issue tracked on GitHub](https://github.com/supabase/cli/issues/4419).

**Solution:**
1. Go to your database settings: `https://supabase.com/dashboard/project/{PROJECT_ID}/database/settings#banned-ips`
2. Check if your IP is listed under "Banned IPs"
3. Click "Unban" to restore access
4. Retry the deployment

<Note>
This typically happens after multiple failed connection attempts or when the connection is interrupted unexpectedly. The ban is temporary and automatic.
</Note>

## Learn More

- [Supabase Edge Functions Documentation](https://supabase.com/docs/guides/functions)
- [Deno Documentation](https://docs.deno.com/)
- [MCP Documentation](https://modelcontextprotocol.io)
- [mcp-use Documentation](/typescript/getting-started)
